#ifndef REALREPRESENTATIONENGINE_HPP
#define REALREPRESENTATIONENGINE_HPP

#include <windows.h>		// windows.h must be included before glut.h to avoid errors.
#include <gl/freeglut.h>
#include <iostream>
#include <lodepng.h>
#include <glfont2.h>
#include <vector>

#include "GameEngine.hpp"
#include "RepresentationEngine.hpp"
#include "RoomElement.hpp"
#include "Scene.hpp"

#define NUMBER_OF_TEXTURES 9

using namespace std;

//Sprites
/*
#define SPRITE_OFFSET 0.015

#define SPRITE_X_0	0.0f
#define SPRITE_X_1	0.1640625f		//  42/256 = 0,1640625
#define SPRITE_X_2	0.328125f		//  84/256 = 0,328125
#define SPRITE_X_3	0.4921875f		// 126/256 = 0,4921875
#define SPRITE_X_4	0.671875f		// 172/256 = 0,671875
#define SPRITE_X_5	0.8359375		// 214/256 = 0,8359375	(limit)

#define SPRITE_Y_4	(1.0f-0.0f-SPRITE_OFFSET)*2
#define SPRITE_Y_3	(1.0f-0.21875f-SPRITE_OFFSET)*2	//  56/256 = 0,21875
#define SPRITE_Y_2	(1.0f-0.4375f-SPRITE_OFFSET)*2	// 112/256 = 0,4375
#define SPRITE_Y_1	(1.0f-0.65625f-SPRITE_OFFSET)*2	// 168/256 = 0,65625
#define SPRITE_Y_0	(1.0f-0.875-SPRITE_OFFSET)*2		// 224/256 = 0,875		(limit)
*/
//Sprites
#define SPRITE_X_0	0.0f
#define SPRITE_X_1	0.1640625f		//  42/256 = 0,1640625
#define SPRITE_X_2	0.328125f		//  84/256 = 0,328125
#define SPRITE_X_3	0.4921875f		// 126/256 = 0,4921875
#define SPRITE_X_4	0.671875f		// 172/256 = 0,671875
#define SPRITE_X_5	0.8359375		// 214/256 = 0,8359375	(limit)

#define SPRITE_Y_4	0.88f-0.0f
#define SPRITE_Y_3	0.66f//1.0f-0.21875f	//  56/256 = 0,21875
#define SPRITE_Y_2	0.44f//1.0f-0.4375f	// 112/256 = 0,4375
#define SPRITE_Y_1	0.22f//1.0f-0.65625f	// 168/256 = 0,65625
#define SPRITE_Y_0  0.0f//1.0f-0.875f		// 224/256 = 0,875		(limit)

//Direction
#define DN	0
#define DS	0
#define DE	0
#define DO	0
#define DNE	0
#define DSE	0
#define DNO	0
#define DSO	0

class GameEngine;

class RealRepresentationEngine : public RepresentationEngine {
private:
    static const float DOOR_DEPTH;

    static const float CAMERA_DEPTH_STEP;
    static const float DEFAULT_CAMERA_DEPTH;
    static const float MAX_CAMERA_DEPTH;
    static const float MIN_CAMERA_DEPTH;

    static const int TEXTURE_BOX;
    static const int TEXTURE_DOOR;
    static const int TEXTURE_FLOOR;
    static const int TEXTURE_GLASS;
    static const int TEXTURE_HERO;
    static const int TEXTURE_MESSAGE;
    static const int TEXTURE_METAL;
    static const int TEXTURE_TITLE;
    static const int TEXTURE_WALL;

    static const float TEXTURE_DOOR_WALL_PROPORTION;
    static const float TEXTURE_FLASH_PROPORTION;
    static const float TEXTURE_PLATFORM_PROPORTION;
    static const float TEXTURE_ROOM_PROPORTION;
    static const float TEXTURE_SWITCH_PROPORTION;

    static const float TEXT_FRAME_MARGIN;
    static const float TEXT_SCALE;

    int delay;
    int anim;
    int seq;

    float cameraDepth;
    float currentCameraDepth;
    Scene* currentScene;
    glfont::GLFont* font;
    GLUquadricObj* quad;
    GLUtesselator* tesselator;
    GLuint textures[NUMBER_OF_TEXTURES];

    void drawCubeWithAdjustedTexture(float width, float height, float depth, int texture);
    void drawCubeWithRepeatedTexture(float width, float height, float depth, int texture, float proportion = 1.0f);
    void drawCubeWithTexture(float width, float height, float depth, int texture, const float textureBounds[3][2]);
    void getLightColor(LightElement* lightElement, float* color);
    void loadTexture(string filePath, int index);
    void LoadTextureKC(char *file,GLuint *text,int *keyColor);
    void represent(Element* element);
    void representBox(BoxElement* boxElement);
    void representDoor(DoorElement* doorElement);
    void representFlash(FlashElement* flashElement);
    void representHero(HeroElement* heroElement);
    void representLight(LightElement* lightElement);
    void representMessage(string* message);
    void representPlatform(PlatformElement* platformElement);
    void representRoom(RoomElement* roomElement);
    void representSpotlight(SpotlightElement* spotlight);
    void representSwitch(SwitchElement* switchElement);
    void render(Scene* scene, bool swapBuffers);
    void drawHero(HeroElement* heroElement,int pos);

public:
    RealRepresentationEngine(GameEngine* gameEngine);
    ~RealRepresentationEngine();

    virtual void init(Menu* menu);
    virtual void init(Scene* scene);
    virtual void render(Menu* menu, Scene* scene);
    virtual void render(Scene* scene);
    virtual void zoomIn();
    virtual void zoomOut();
};

#endif
